home *** CD-ROM | disk | FTP | other *** search
- /*-
- * DEVICE2.C
- *
- * The xpkdisk.device code that makes it a real Exec .device.
- * Mostly based on the 1.1 RKM example and Matt Dillon's library code.
- *
- * $Id: device2.c,v 1.5 1995/04/08 20:21:52 Rhialto Exp $
- * $Log: device2.c,v $
- * Revision 1.5 1995/04/08 20:21:52 Rhialto
- * Add/correct version strings.
- *
- * Revision 1.4 1995/04/02 14:58:51 Rhialto
- * Change #ifdef into #if.
- * Update for DICE 3.0. Lots more casts.
- *
- * Revision 1.3 1993/11/08 13:11:15 Rhialto
- * Add RCS tags.
- *
- *
- * This code is (C) Copyright 1989-1995 by Olaf Seibert. All rights reserved.
- * May not be used or copied without a licence.
- -*/
-
- #include "xpkdisk.h"
- #include <exec/initializers.h>
-
- #if DEBUG
- # include "syslog.h"
- #else
- # define debug(x)
- #endif
- /* INDENT ON */
-
- Prototype __geta4 DEV *Init(__A0 long segment, __D0 struct XpkDiskDevice *dev, __A6 struct ExecBase *execbase);
- Prototype __geta4 void DevOpen(__D0 ulong unitno, __D1 ulong flags, __A1 struct IOStdReq *ioreq, __A6 DEV *dev);
- Prototype __geta4 long DevClose(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
- Prototype __geta4 long DevExpunge(__A6 DEV *dev);
- Prototype __geta4 void DevBeginIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
- Prototype __geta4 long DevAbortIO(__A1 struct IOStdReq *ioreq, __A6 DEV *dev);
-
- Prototype void TermIO(struct IOStdReq *ioreq);
- Prototype void WakePort(struct MsgPort *port);
- Prototype __geta4 void UnitTask(void);
- Prototype void CMD_Invalid(struct IOStdReq *ioreq, UNIT *unit);
- Prototype void CMD_Stop(struct IOStdReq *ioreq, UNIT *unit);
- Prototype void CMD_Start(struct IOStdReq *ioreq, UNIT *unit);
- Prototype void CMD_Flush(struct IOStdReq *ioreq, UNIT *unit);
-
- Prototype const char DevName[];
- Prototype const char idString[];
-
- const char DevName[] = "xpkdisk.device";
- const char idString[] = "\0$VER: xpkdisk.device " STR(VERSION) "." STR(REVISION) "\r\n";
- static const char rcsId[] = "$Id: device2.c,v 1.5 1995/04/08 20:21:52 Rhialto Exp $";
-
- /*
- * Device commands:
- */
-
- void (*const funcTable[]) (struct IOStdReq *, UNIT *) = {
- CMD_Invalid, CMD_Reset, CMD_Read, CMD_Write, CMD_Update, CMD_Clear,
- CMD_Stop, CMD_Start, CMD_Flush, TD_Motor, TD_Seek, TD_Format,
- TD_Remove, TD_Changenum, TD_Changestate, TD_Protstatus, TD_Rawread,
- TD_Rawwrite, TD_Getdrivetype, TD_Getnumtracks, TD_Addchangeint,
- TD_Remchangeint, TD_Getgeometry, TD_Eject,
- };
-
- #define LAST_TD_COMM TD_EJECT
-
- long SysBase; /* Argh! A global variable! */
-
- /*
- * The Initialization routine is given a seglist pointer, the device
- * base pointer, and the Exec base pointer. We are being called from
- * InitResident. Exec has Forbid() for us during the call.
- */
-
-
- __geta4 DEV *
- Init(segment, dev, execbase)
- __A0 long segment;
- __D0 DEV *dev;
- __A6 struct ExecBase *execbase;
- {
- SysBase = *(long *) 4;
- #if DEBUG
- initsyslog();
- debug(("seg %lx, dev %lx, sys %lx\n", segment, dev, execbase));
- #endif
- if (DevInit(dev)) {
- dev->xd_Seglist = segment;
- debug(("Init done.\n"));
- return dev;
- }
- FreeMem((char *) dev - dev->dev_NegSize, dev->dev_NegSize + dev->dev_PosSize);
- return NULL;
- }
-
- /*
- * Open is given the device pointer, unitno and flags. Either return the
- * device pointer or NULL. Remove the DELAYED-EXPUNGE flag. Exec has
- * Forbid() for us during the call.
- */
-
- __geta4 void
- DevOpen(unitno, flags, ioreq, dev)
- __D0 ulong unitno;
- __D1 ulong flags;
- __A1 struct IOStdReq *ioreq;
- __A6 DEV *dev;
- {
- UNIT *unit;
-
- debug(("OpenDevice %lx unit %ld, flags %lx\n", dev, unitno, flags));
- ++dev->dev_OpenCnt;
- if (unitno >= XD_NUMUNITS)
- goto error;
-
- if ((unit = dev->xd_Unit[unitno]) == NULL) {
- debug(("Call UnitInit\n"));
- if ((unit = UnitInit(dev, unitno)) == NULL)
- goto error;
- debug(("UnitInit succeeded: %x\n", unit));
- dev->xd_Unit[unitno] = unit;
- }
- ioreq->io_Unit = (struct Unit *) unit;
-
- ++unit->xu_OpenCnt;
- dev->dev_Flags &= ~LIBF_DELEXP;
- ioreq->io_Error = 0;
-
- debug(("DevOpen: success\n"));
- return;
-
- error:
- --dev->dev_OpenCnt;
- ioreq->io_Error = IOERR_OPENFAIL;
- debug(("DevOpen: fail\n"));
- }
-
- /*
- * Close is given the device pointer and the io request. Be sure not to
- * decrement the open count if already zero. If the open count is or
- * becomes zero AND there is a LIBF_DELEXP, we expunge the device and
- * return the seglist. Otherwise we return NULL.
- *
- * Note that this routine never sets LIBF_DELEXP on its own.
- *
- * Exec has Forbid() for us during the call.
- */
-
- __geta4 long
- DevClose(ioreq, dev)
- __A1 struct IOStdReq *ioreq;
- __A6 DEV *dev;
- {
- UNIT *unit;
-
- unit = (UNIT *) ioreq->io_Unit;
- debug(("CloseDevice io %08lx unit %08lx\n", ioreq, unit));
-
- /*
- * See if the unit is still in use. If not, close it down.
- */
-
- if (unit->xu_OpenCnt && --unit->xu_OpenCnt == 0) {
- dev->xd_Unit[unit->xu_UnitNr] = NULL;
- UnitCloseDown(ioreq, dev, unit);
- }
- /*
- * Make sure the ioreq is not used again.
- */
- ioreq->io_Unit = (void *) -1;
- ioreq->io_Device = (void *) -1;
-
- if (dev->dev_OpenCnt && --dev->dev_OpenCnt)
- return NULL;
- if (dev->dev_Flags & LIBF_DELEXP)
- return DevExpunge(dev);
- return NULL;
- }
-
- /*
- * We expunge the device and return the Seglist ONLY if the open count is
- * zero. If the open count is not zero we set the DELAYED-EXPUNGE
- * flag and return NULL.
- *
- * Exec has Forbid() for us during the call. NOTE ALSO that Expunge might be
- * called from the memory allocator and thus we CANNOT DO A Wait() or
- * otherwise take a long time to complete (straight from RKM).
- *
- * Apparently RemLibrary(lib) calls our expunge routine and would therefore
- * freeze if we called it ourselves. As far as I can tell from RKM,
- * DevExpunge(lib) must remove the device itself as shown below.
- */
-
- __geta4 long
- DevExpunge(dev)
- __A6 DEV *dev;
- {
- long Seglist;
-
- if (dev->dev_OpenCnt) {
- dev->dev_Flags |= LIBF_DELEXP;
- return NULL;
- }
- Remove(&dev->dev_Node);
- DevCloseDown(dev); /* Should be quick! */
- #if DEBUG
- uninitsyslog();
- #endif
- Seglist = dev->xd_Seglist;
- FreeMem((char *) dev - dev->dev_NegSize,
- (long) dev->dev_NegSize + dev->dev_PosSize);
- return Seglist;
- }
-
- /*
- * BeginIO entry point. We don't handle any QUICK requests, we just send
- * the request to the proper unit to handle.
- */
-
- __geta4 void
- DevBeginIO(ioreq, dev)
- __A1 struct IOStdReq *ioreq;
- __A6 DEV *dev;
- {
- UNIT *unit;
-
- /*
- * Bookkeeping.
- */
- unit = (UNIT *) ioreq->io_Unit;
- debug(("BeginIO: %x io %08lx dev %08lx u %08lx\n", ioreq->io_Command,
- ioreq, dev, unit));
-
- /*
- * See if the io command is within range.
- */
- if (STRIP(ioreq->io_Command) > LAST_TD_COMM)
- goto NoCmd;
-
- #if HANDLE_IO_QUICK
- Forbid(); /* Disable(); is a bit too strong for us. */
- #endif
-
- /*
- * Process all immediate commands no matter what. Don't even require
- * an exclusive lock on the unit.
- */
- if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
- goto Immediate;
-
- /*
- * We don't handle any QUICK I/O since that only gives trouble with
- * message ports and so. Other devices normally would include the code
- * below.
- */
- #if HANDLE_IO_QUICK
- /*
- * See if the user does not request QUICK IO. If not, it is likely to
- * be async and therefore we don't do it sync.
- */
- if (!(ioreq->io_Flags & IOF_QUICK))
- goto NoQuickRequested;
-
- /*
- * See if the unit is STOPPED. If so, queue the msg.
- */
- if (unit->xu_Flags & UNITF_STOPPED)
- goto QueueMsg;
-
- /*
- * This is not an immediate command. See if the device is busy. If
- * not, process the action in this (the caller's) context.
- */
- if (!BSET_ACTIVE(&unit->xu_Flags))
- goto Immediate;
- #endif
-
- /*
- * We need to queue the device. Clear the QUICK flag.
- */
- QueueMsg:
- ioreq->io_Flags &= ~IOF_QUICK;
- NoQuickRequested:
- #if HANDLE_IO_QUICK
- Permit(); /* Enable(); is a bit too strong for us. */
- #endif
- PutMsg(&unit->xu_Port, &ioreq->io_Message);
-
- return;
-
- Immediate:
- #if HANDLE_IO_QUICK
- Permit(); /* Enable(); is a bit too strong for us. */
- #endif
- debug(("BeginIO: Immediate\n"));
- ioreq->io_Error = TDERR_NoError;
- PerformIO(ioreq, unit);
- return;
-
- NoCmd:
- ioreq->io_Error = IOERR_NOCMD;
- TermIO(ioreq);
- return;
-
- }
-
- /*
- * Terminate an io request. Called (normally) for every BeginIO. 'Funny'
- * commands that don't call TermIO, or call it multiple times, may not be
- * properly handled unless you are careful. TD_ADDCHANGEINT and
- * TD_REMCHANGEINT are obvious examples.
- */
-
- void
- TermIO(ioreq)
- register struct IOStdReq *ioreq;
- {
- register UNIT *unit;
-
- unit = (UNIT *) ioreq->io_Unit;
- debug(("TermIO: io %08lx u %08lx %ld %ld\n", ioreq, unit,
- ioreq->io_Actual, (long)ioreq->io_Error));
-
- #if HANDLE_IO_QUICK
- /*
- * Since immediate commands don't even require an exclusive lock on
- * the unit, don't unlock it.
- */
- if (IMMEDIATE & (1L << STRIP(ioreq->io_Command)))
- goto Immediate;
-
- /*
- * We may need to turn the active (lock) bit off, but not if we are
- * within the task.
- */
- if (unit->xu_Flags & UNITF_INTASK)
- goto Immediate;
-
- unit->xu_Flags &= ~UNITF_ACTIVE;
-
- /*
- * The task may have work to do that came in while we were processing
- * in the caller's context.
- */
- if (unit->xu_Flags & UNITF_WAKETASK) {
- unit->xu_Flags &= ~UNITF_WAKETASK;
- WakePort(&unit->xu_Port);
- }
- #endif
-
- Immediate:
- /*
- * If the quick bit is still set then wen don't need to reply the msg
- * -- just return to the user.
- */
-
- if (!(ioreq->io_Flags & IOF_QUICK))
- ReplyMsg(&ioreq->io_Message);
-
- return;
- }
-
- /*
- * AbortIO entry point. We try to abort IO here.
- */
-
- __geta4 long
- DevAbortIO(ioreq, dev)
- __A1 struct IOStdReq *ioreq;
- __A6 DEV *dev;
- {
- Forbid();
- if (ioreq->io_Flags & IOF_QUICK ||
- IMMEDIATE & (1L << STRIP(ioreq->io_Command))) {
- Permit();
- return 1;
- } else {
- Remove(&ioreq->io_Message.mn_Node);
- Permit();
- ioreq->io_Error = IOERR_ABORTED;
- ReplyMsg(&ioreq->io_Message);
-
- return 0;
- }
- }
-
- void
- WakePort(port)
- register struct MsgPort *port;
- {
- Signal(port->mp_SigTask, 1L << port->mp_SigBit);
- }
-
- /*
- * This is the main loop of the Unit tasks. It must be very careful with
- * global data.
- */
-
- __geta4 void
- UnitTask(void)
- {
- UNIT *unit;
- long waitmask;
- struct IOExtTD *ioreq;
-
- debug(("Start UnitTask\n"));
- {
- struct Task *task;
-
- task = FindTask(NULL);
- unit = (UNIT *) task->tc_UserData;
- /* dev = unit->xu_Dev; */
- task->tc_UserData = NULL;
- debug(("task %lx unit %lx\n", task, unit));
- }
-
- /*
- * Now finish initializing the message ports and other signal things
- */
-
- waitmask = UnitInit2(unit);
- WakePort(&unit->xu_Port);
-
- for (;;) {
- debug(("Task: Waiting...\n"));
- Wait(waitmask);
-
- PollTimer(unit);
-
- /*
- * See if we are stopped.
- */
- if (unit->xu_Flags & UNITF_STOPPED)
- continue;
-
- #if HANDLE_IO_QUICK
- /*
- * Lock the device. If it fails, we have set a flag such that the
- * TermIO wakes us again.
- */
- unit->xu_Flags |= UNITF_WAKETASK;
- if (BSET_ACTIVE(&unit->xu_Flags))
- continue;
-
- unit->xu_Flags |= UNITF_INTASK;
- #endif
-
- while (ioreq = (struct IOExtTD *) GetMsg(&unit->xu_Port)) {
- debug(("Task: io %08lx %lx\n", ioreq, (long)ioreq->iotd_Req.io_Command));
- ioreq->iotd_Req.io_Error = 0;
- if (ioreq->iotd_Req.io_Command == CMD_Die)
- goto die;
- PerformIO((&ioreq->iotd_Req), unit);
- }
-
- #if HANDLE_IO_QUICK
- unit->xu_Flags &= ~(UNITF_ACTIVE | UNITF_INTASK | UNITF_WAKETASK);
- #endif
- }
-
- die:
- debug(("Aaargh! They stabbed me!\n"));
- UnitCloseDown2(unit);
- debug(("I'm gonna dieeeeeeeeeeee___________ .......\n"));
- Forbid();
- ioreq->iotd_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
- Signal((struct Task *)ioreq->iotd_Req.io_Message.mn_ReplyPort, SIGF_SINGLE);
- /* fall off the end of the world */
- }
-
- void
- CMD_Invalid(ioreq, unit)
- struct IOStdReq *ioreq;
- UNIT *unit;
- {
- ioreq->io_Error = IOERR_NOCMD;
- TermIO(ioreq);
- }
-
- void
- CMD_Stop(ioreq, unit)
- struct IOStdReq *ioreq;
- UNIT *unit;
- {
- unit->xu_Flags |= UNITF_STOPPED;
- TermIO(ioreq);
- }
-
- void
- CMD_Start(ioreq, unit)
- struct IOStdReq *ioreq;
- UNIT *unit;
- {
- unit->xu_Flags &= ~UNITF_STOPPED;
- WakePort(&unit->xu_Port);
- TermIO(ioreq);
- }
-
- void
- CMD_Flush(ioreq, unit)
- struct IOStdReq *ioreq;
- UNIT *unit;
- {
- register struct IOStdReq *req;
-
- /* Flush our own command queue */
- Forbid();
- while (req = (struct IOStdReq *) GetMsg(&unit->xu_Port)) {
- req->io_Error = IOERR_ABORTED;
- ReplyMsg(&req->io_Message);
- }
- Permit();
-
- WakePort(&unit->xu_Port);
- TermIO(ioreq);
- }
-